#pragma once

#include<iostream>
#include<vector>
#include<semaphore.h>
#include<pthread.h>

using namespace std;

const static int defaultcap=5;

//基于环形队列实现“生产消费模型”
template <class T>
class RingQueue
{
private:
    //对信号量进行--操作
    void P(sem_t& sem)
    {
        sem_wait(&sem);
    }
    //对信号量进行++操作
    void V(sem_t& sem)
    {
        sem_post(&sem);
    }
    void lock(pthread_mutex_t& mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void unlock(pthread_mutex_t& mutex)
    {
        pthread_mutex_unlock(&mutex);
    }
public:
    RingQueue(int cap=defaultcap):_RingQueue(cap),_cap(cap),c_step_(0),p_step_(0)
    {
        sem_init(&p_space_sem,0,cap);
        sem_init(&c_data_sem,0,0);

        pthread_mutex_init(&p_mutex,nullptr);
        pthread_mutex_init(&c_mutex,nullptr);
    }
    //向环形队列插入数据
    void push(const T& in)
    {
        //生产，就是空间——>数据,即p_space_sem++  c_data_sem--
        P(p_space_sem);

        lock(p_mutex);

        usleep(10);
        _RingQueue[p_step_++]=in;
        p_step_%=_cap;//维持环形特征

        unlock(p_mutex);

        V(c_data_sem);
    }
    //从环形队列里拿出数据
    void pop(T* out)
    {
        P(c_data_sem);

        lock(c_mutex);
        usleep(10);

        *out=_RingQueue[c_step_++];
        c_step_%=_cap;//维持环形特征

        unlock(c_mutex);

        V(p_space_sem);
    }
    ~RingQueue()
    {
        sem_destroy(&p_space_sem);
        sem_destroy(&c_data_sem);

        pthread_mutex_destroy(&p_mutex);
        pthread_mutex_destroy(&c_mutex);
    }

private:
    vector<T> _RingQueue;
    int _cap;

    int c_step_;//生产者下标
    int p_step_;//消费者下标

    sem_t p_space_sem;//生产者关注的空间资源
    sem_t c_data_sem;//消费者关注的数据资源

    pthread_mutex_t p_mutex;//生产者加锁
    pthread_mutex_t c_mutex;//消费者加锁
};